package com.zky.gulimall.cart.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.zky.common.utils.R;
import com.zky.common.vo.MemberRespVo;
import com.zky.gulimall.cart.feign.ProductFeignService;
import com.zky.gulimall.cart.interceptor.CartInterceptor;
import com.zky.gulimall.cart.service.CartService;
import com.zky.gulimall.cart.vo.Cart;
import com.zky.gulimall.cart.vo.CartItem;
import com.zky.gulimall.cart.vo.SkuInfoVo;
import com.zky.gulimall.cart.vo.UserInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * @Description 购物车
 * @Author 张开源
 * @Date 2022/12/5 21:46
 * @Version 1.0
 **/
@Service("cartService")
@Slf4j
public class CartServiceImpl implements CartService {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private ProductFeignService productFeignService;
    @Autowired
    private ThreadPoolExecutor executor;

    private static final String CART_PREFIX = "zky:cart:";

    @Override
    public CartItem addToCart(Long skuId, Integer num) throws ExecutionException, InterruptedException {

        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        Object result = cartOps.get(String.valueOf(skuId));
        if (Objects.isNull(result)) {
            //购物车无商品，添加新商品
            //添加新商品到购物车
            CartItem cartItem = new CartItem();
            CompletableFuture<Void> skuInfo = CompletableFuture.runAsync(() -> {
                //查询远程商品信息
                R info = productFeignService.info(skuId);
                if (!info.isSuccess()) {
                    log.error("addToCart info resultMsg:{}", info.getMsg());
                    throw new RuntimeException("商品信息查询失败");
                }

                String data = JSON.toJSONString(info.get("skuInfo"));
                SkuInfoVo skuInfoVo = JSON.parseObject(data, new TypeReference<SkuInfoVo>() {
                });

                if (skuInfoVo == null) {
                    throw new RuntimeException("查询商品信息为空");
                }
                cartItem.setCheck(true);
                cartItem.setCount(num);
                cartItem.setImage(skuInfoVo.getSkuDefaultImg());
                cartItem.setTitle(skuInfoVo.getSkuTitle());
                cartItem.setSkuId(skuId);
                cartItem.setPrice(skuInfoVo.getPrice());
            }, executor);

            CompletableFuture<Void> attrValueQuery = CompletableFuture.runAsync(() -> {
                //远程查询sku组合属性信息
                List<String> attrValues = productFeignService.getSkuSaleAttrValues(skuId);
                cartItem.setSkuAttrs(attrValues);
            }, executor);

            //异步操作，等线程处理结束
            CompletableFuture.allOf(skuInfo, attrValueQuery).get();

            //加入redis
            cartOps.put(String.valueOf(skuId), JSON.toJSONString(cartItem));
            return cartItem;
        } else {
            //g购物车已经存在商品,去修改商品数量
            CartItem item = JSON.parseObject(String.valueOf(result), CartItem.class);
            item.setCount(item.getCount() + num);

            //修改redis
            cartOps.put(String.valueOf(skuId), JSON.toJSONString(item));
            return item;
        }
    }

    @Override
    public CartItem getCartItem(Long skuId) {
        log.warn("getCartItem  skuId:{}", skuId);
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        Object result = cartOps.get(String.valueOf(skuId));
        CartItem cartItem = null;
        if (!Objects.isNull(result)) {
            cartItem = JSON.parseObject(String.valueOf(result), CartItem.class);
        }
        log.warn("getCartItem  cartItem:{}", cartItem);
        return cartItem;
    }

    @Override
    public Cart getCart() throws ExecutionException, InterruptedException {
        //判断是否登陆
        UserInfo userInfo = CartInterceptor.threadLocal.get();
        Cart cart = new Cart();
        if (userInfo.getUserId() != null) {
            //登陆状态
            String cartKey = CART_PREFIX + userInfo.getUserId();
            //判断临时购物车是否有商品，若有商品则需合并
            //获取临时购物车
            List<CartItem> tempCartItems = getCartItems(CART_PREFIX + userInfo.getUserKey());
            if (!CollectionUtils.isEmpty(tempCartItems)) {
                //临时购物车有数据，需要合并
                for (CartItem tempCartItem : tempCartItems) {
                    addToCart(tempCartItem.getSkuId(), tempCartItem.getCount());
                }

                //清除临时购物车数据
                clearCart(CART_PREFIX + userInfo.getUserKey());
            }
            //获取登陆后购物车数据,合并后数据
            List<CartItem> cartItems = getCartItems(cartKey);
            cart.setItems(cartItems);
        } else {
            //未登录
            String cartKey = CART_PREFIX + userInfo.getUserKey();
            List<CartItem> cartItems = getCartItems(cartKey);
            cart.setItems(cartItems);
        }
        return cart;
    }


    /**
     * 获取待操作购物车
     *
     * @return
     */
    private BoundHashOperations<String, Object, Object> getCartOps() {
        //判断是否登陆
        UserInfo userInfo = CartInterceptor.threadLocal.get();
        log.warn("addToCart userInfo:{}", userInfo);
        String cartKey = "";
        if (userInfo.getUserId() != null) {
            //登陆购物车前缀
            cartKey = CART_PREFIX + userInfo.getUserId();
        } else {
            //临时购物车前缀
            cartKey = CART_PREFIX + userInfo.getUserKey();
        }

        BoundHashOperations<String, Object, Object> boundHashOps = redisTemplate.boundHashOps(cartKey);
        return boundHashOps;
    }

    private List<CartItem> getCartItems(String cartKey) {
        BoundHashOperations<String, Object, Object> hashOps = redisTemplate.boundHashOps(cartKey);
        List<Object> values = hashOps.values();
        if (!CollectionUtils.isEmpty(values)) {
            List<CartItem> cartItems = values.stream().map(item -> {
                String value = String.valueOf(item);
                CartItem cartItem = JSON.parseObject(value, CartItem.class);
                return cartItem;
            }).collect(Collectors.toList());
            return cartItems;
        }
        return null;
    }


    @Override
    public void clearCart(String cartKey) {
        redisTemplate.delete(cartKey);
    }

    @Override
    public void checkItem(Long skuId, Integer check) {
        CartItem cartItem = getCartItem(skuId);
        cartItem.setCheck(check == 1 ? true : false);
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        cartOps.put(String.valueOf(skuId), JSON.toJSONString(cartItem));
    }

    @Override
    public void changeCartItemCount(Long skuId, Integer count) {
        CartItem cartItem = getCartItem(skuId);
        cartItem.setCount(count);
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        cartOps.put(String.valueOf(skuId), JSON.toJSONString(cartItem));
    }

    @Override
    public void deleteCartItemBySkuId(Long skuId) {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        cartOps.delete(skuId.toString());
    }

    @Override
    public List<CartItem> userCartItems() {
        UserInfo userInfo = CartInterceptor.threadLocal.get();
        if (userInfo == null) {
            return null;
        }
        List<CartItem> cartItems = getCartItems(CART_PREFIX + userInfo.getUserId());
        List<CartItem> checkedCartItems = null;
        if (!CollectionUtils.isEmpty(cartItems)) {
            checkedCartItems = cartItems.stream().filter(item -> item.getCheck()).map(e -> {
                try {
                    //更新最新价格
                    R result = productFeignService.getPrice(e.getSkuId());
                    if (result.isSuccess()) {
                        String data = JSON.toJSONString(result.get("data"));
                        if (!StringUtils.isEmpty(data)) {
                            BigDecimal bigDecimal = JSON.parseObject(data, new TypeReference<BigDecimal>() {
                            });
                            e.setPrice(bigDecimal);
                        }
                    }
                } catch (Exception exception) {
                    exception.printStackTrace();
                }
                return e;
            }).collect(Collectors.toList());
        }

        return checkedCartItems;
    }

    public static void main(String[] args) {
        System.out.println(JSON.toJSONString(null));
    }
}
